import { forwardRef, useEffect, useState } from 'react'
import {
  black_keys_left,
  playerOnIndex,
  musicWhiteKey,
  musicBlackKey,
} from '@/lib/music/data'
import style from './music.module.scss'
import { isPhoneEquipment, sleep } from '@/utils/common'
import pianoPlayerEvent, { type MusicKey } from '@/event/pianoPlayerEvent'
import { musicBasicSettingStore } from '@/store/musicBasicSettingStore'
import { observer } from 'mobx-react'
import { MusicPlayerSong } from '@/types/music'
import {
  AutoPlaySongController,
  PianoRef,
} from '@/lib/music/AutoPlaySongController'

interface Props {
  // volume?: number
  // showKeyCode?: boolean
  // showNote?: boolean
}

/**
 * 钢琴组件
 * @param porps
 * @param ref
 * @returns
 */
function Piano(_porps: Props, ref?: React.ForwardedRef<PianoRef>) {
  const [activeWhiteKeys, setActiveWhiteKeys] = useState([] as number[])
  const [activeBlackKeys, setActiveBlackKeys] = useState([] as number[])
  const [scale, setScale] = useState(1)
  function playMusic(index: number, white: boolean = true) {
    playerOnIndex(index, white)
  }
  const onMouseDown = (index: number, white: boolean = true) => {
    return (e: React.MouseEvent | React.TouchEvent) => {
      if (!e?.nativeEvent) {
        return
      }

      playMusic(index, white)
      if (white) {
        setActiveWhiteKeys((keys) => [...keys, index])
      } else {
        setActiveBlackKeys((keys) => [...keys, index])
      }
    }
  }
  const setKeyActive = (key: MusicKey, active: boolean = true) => {
    const white = musicWhiteKey.find((item) => item.music == key.music)
    const index = white
      ? musicWhiteKey.findIndex((item) => item.music == key.music)
      : musicBlackKey.findIndex((item) => item.music == key.music)
    if (index == -1) {
      console.warn('key not found :' + key)
      return
    }
    if (white) {
      if (active) {
        setActiveWhiteKeys((keys) => [...keys, index])
        return
      }
      setActiveWhiteKeys((keys) => {
        if (keys.includes(index)) return keys.filter((key) => key != index)
        return keys
      })
    } else {
      if (active) {
        setActiveBlackKeys((keys) => [...keys, index])
        return
      }
      setActiveBlackKeys((keys) => {
        if (keys.includes(index)) return keys.filter((key) => key != index)
        return keys
      })
    }
  }
  const onMouseUp = (index: number, white: boolean = true) => {
    return () => {
      if (white) {
        setActiveWhiteKeys((keys) =>
          keys.includes(index) ? keys.filter((key) => key != index) : keys
        )
      } else {
        setActiveBlackKeys((keys) =>
          keys.includes(index) ? keys.filter((key) => key != index) : keys
        )
      }
    }
  }
  const onMouseEnter = (index: number, white: boolean = true) => {
    return (e: React.MouseEvent<HTMLDivElement>) => {
      if (isPhoneEquipment()) return
      if (e.buttons == 1) onMouseDown(index, white)(e)
    }
  }
  const onTouchUp = (index: number, white: boolean = true) => {
    return (e: React.TouchEvent<HTMLDivElement>) => {
      if (e.touches.length == 0) {
        setActiveBlackKeys((keys) => {
          if (keys.length != 0) {
            return []
          }
          return keys
        })
        setActiveWhiteKeys((keys) => {
          if (keys.length != 0) {
            return []
          }
          return keys
        })
      } else {
        if (white) {
          setActiveWhiteKeys((keys) =>
            keys.includes(index) ? keys.filter((key) => key != index) : keys
          )
        } else {
          setActiveBlackKeys((keys) =>
            keys.includes(index) ? keys.filter((key) => key != index) : keys
          )
        }
      }
    }
  }
  useEffect(() => {
    const onKeyDown = (e: KeyboardEvent) => {
      if (e.repeat) {
        return
      }
      if (e.shiftKey) {
        const index2 = musicBlackKey.findIndex(
          (item) => e.key.toUpperCase() == item.keyboard
        )
        if (index2 !== -1) {
          playMusic(index2, false)
          setActiveBlackKeys((keys) => [...keys, index2])
          return
        }
      } else {
        const index = musicWhiteKey.findIndex(
          (item) => e.key.toLowerCase() == item.keyboard
        )
        if (index == -1) {
          return
        }
        playMusic(index)
        setActiveWhiteKeys((keys) => [...keys, index])
      }
    }
    const onKeyUp = (e: KeyboardEvent) => {
      if (e.key == 'Shift' && !e.shiftKey) {
        setActiveBlackKeys([])
        return
      }
      if (e.shiftKey) {
        const index = musicBlackKey.findIndex(
          (item) => e.key.toUpperCase() == item.keyboard
        )
        if (index == -1) {
          return
        }
        setActiveBlackKeys((keyIndex) => {
          if (keyIndex.includes(index)) {
            return keyIndex.filter((key) => key != index)
          }
          return keyIndex
        })
      } else {
        const index = musicWhiteKey.findIndex(
          (item) => e.key.toLowerCase() == item.keyboard
        )
        if (index == -1) {
          return
        }
        setActiveWhiteKeys((keyIndex) => {
          if (keyIndex.includes(index)) {
            return keyIndex.filter((key) => key != index)
          }
          return keyIndex
        })
      }
    }
    window.addEventListener('keydown', onKeyDown)
    window.addEventListener('keyup', onKeyUp)
    return () => {
      window.removeEventListener('keydown', onKeyDown)
      window.removeEventListener('keyup', onKeyUp)
    }
  })
  useEffect(() => {
    const u1 = pianoPlayerEvent.on('onKeyActive', (key, active) => {
      setKeyActive(key, active)
    })
    const u2 = pianoPlayerEvent.on('playerSong', (song, ref) => {
      const autoPlayer = new AutoPlaySongController(song)
      ref.current = autoPlayer
      autoPlayer.play()
    })
    return () => {
      u1()
      u2()
    }
  }, [])
  // 尺寸自适应
  useEffect(() => {
    function resize() {
      const width = 36 * 45 + 150
      // if (width > window.innerWidth) {
      setScale(window.innerWidth / width)
      // } else {
      // setScale(1)
      // }
    }
    window.addEventListener('resize', resize)
    resize()
    return () => {
      window.removeEventListener('resize', resize)
    }
  }, [])
  const isActive = (index: number, white: boolean = true) => {
    if (white) {
      return activeWhiteKeys.includes(index)
    } else {
      return activeBlackKeys.includes(index)
    }
  }
  if (ref) {
    const refInstance: PianoRef = {
      playerSong: (song: MusicPlayerSong, onend?: () => any) => {
        const autoPlayer = new AutoPlaySongController(song)
        onend && autoPlayer.onEnd(onend)
        autoPlayer.play()
        return autoPlayer
      },
    }
    // @ts-ignore
    ref.current = refInstance
  }

  return (
    <div
      className={style['piano-wapper']}
      style={{
        // @ts-ignore
        '--scale': scale,
      }}>
      <div className={style['piano']} style={{ transform: `scale(${scale})` }}>
        <div className={style['keys-container']}>
          {musicWhiteKey.map((item, index) => {
            return (
              <div
                className={style['key-wapper']}
                key={index}
                onMouseDown={onMouseDown(index)}
                onMouseEnter={onMouseEnter(index)}
                onMouseLeave={onMouseUp(index)}
                onMouseUp={onMouseUp(index)}
                onTouchStart={onMouseDown(index)}
                onTouchEnd={onTouchUp(index)}>
                <div
                  className={
                    style['key'] +
                    (isActive(index) ? ' ' + style['key-active'] : '')
                  }>
                  {musicBasicSettingStore.value.showKeyCode && (
                    <div className={style['key1']}>{item.keyboard}</div>
                  )}
                  {musicBasicSettingStore.value.showNote && (
                    <div className={style['key2']}>{item.music}</div>
                  )}
                </div>
              </div>
            )
          })}
          {musicBlackKey.map((item, index) => {
            return (
              <div
                className={
                  style['block-key'] +
                  (isActive(index, false)
                    ? ` ${style['block-key-active']}`
                    : '')
                }
                style={{
                  // @ts-ignore
                  '--left': black_keys_left[index],
                }}
                onMouseDown={onMouseDown(index, false)}
                onMouseEnter={onMouseEnter(index, false)}
                onMouseLeave={onMouseUp(index, false)}
                onMouseUp={onMouseUp(index, false)}
                onTouchStart={onMouseDown(index, false)}
                onTouchEnd={onTouchUp(index, false)}
                key={index}>
                <div className={style['key1']}>
                  {musicBasicSettingStore.value.showKeyCode && item.keyboard}
                </div>
                <div className={style['key2']}>
                  {musicBasicSettingStore.value.showNote && item.music}
                </div>
              </div>
            )
          })}
          <div className={style['top-mask']}>
            <div className={style['logo']}>Learning knows no bounds</div>
          </div>
        </div>
      </div>
    </div>
  )
}
export default observer(forwardRef(Piano))
